// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstring>
#include <cstdlib>
#include <securec.h>
#include "CasLog.h"
#include "CasMsg.h"
#include "CasStreamBuildSender.h"

CasStreamBuildSender::CasStreamBuildSender(CasSocket *socket)
{
    this->m_socket = socket;
}

CasStreamBuildSender::~CasStreamBuildSender()
{
    this->m_socket = nullptr;
}

int CasStreamBuildSender::SendDataToServer(CasMsgType type, const void *buf, size_t len)
{
    if (m_socket == nullptr) {
        ERR("Failed to send data, socket is null.");
        return -1;
    }

    stream_msg_head_t msgHead;
    msgHead.size = len;
    switch (type) {
        case (Audio):
            msgHead.checksum = CAS_MSG_CHECKSUM_AUDIO;
            break;
        case (Recorder):
            msgHead.checksum = CAS_MSG_CHECKSUM_RECORD;
            break;
        case (CmdControl):
            msgHead.checksum = CAS_MSG_CHECKSUM_CONTROL;
            break;
        case (TouchInput):
            msgHead.checksum = CAS_MSG_CHECKSUM_TOUCH_INPUT;
            break;
        case (Orientation):
            msgHead.checksum = CAS_MSG_CHECKSUM_ORIENTATION;
            break;
        case (Video):
            msgHead.checksum = CAS_MSG_CHECKSUM_VIDEO;
            break;
        case (Verify):
            msgHead.checksum = CAS_MSG_CHECKSUM_VERIFY;
            break;
        case (HeartBeat):
            msgHead.checksum = CAS_MSG_CHECKSUM_HEARTBEAT;
            break;
        case (ImeData):
            msgHead.checksum = CAS_MSG_CHECKSUM_IMEDATA;
            break;
        case (KeyEventInput):
            msgHead.checksum = CAS_MSG_CHECKSUM_KEYEVENTINPUT;
            break;
        case (MotionEventInput):
            msgHead.checksum = CAS_MSG_CHECKSUM_MOTIONEVENTINPUT;
            break;
        case (Channel):
            msgHead.checksum = CAS_MSG_CHECKSUM_CHANNEL;
            break;
        case (VirtualCamera):
            msgHead.checksum = CAS_MSG_CHECKSUM_VIRTUAL_CAMERA;
            break;
        case (VirtualMicrophone):
            msgHead.checksum = CAS_MSG_CHECKSUM_VIRTUAL_MICROPHONE;
            break;
        case (VirtualSensor):
            msgHead.checksum = CAS_MSG_CHECKSUM_VIRTUAL_SENSOR;
            break;
        default: {
            return -1;
        }
    }
    msgHead.SetPayloadSize(len);
    msgHead.magicword = CAS_STREAM_DELIMITER_MAGICWORD;
    msgHead.type = type;

    size_t dataLen = sizeof(stream_msg_head_t) + len;
    char *outBuffer = (char *)malloc(dataLen);
    if (outBuffer == nullptr) {
        ERR("Failed to malloc out buffer.");
        return 0;
    }
    if (EOK != memcpy_s(outBuffer, dataLen, &msgHead, sizeof(stream_msg_head_t))) {
        ERR("Copy msg head fail.");
        free(outBuffer);
        return 0;
    }
    if (EOK != memcpy_s(outBuffer + sizeof(stream_msg_head_t), dataLen - sizeof(stream_msg_head_t), buf, len)) {
        ERR("Copy msg data fail.");
        free(outBuffer);
        return 0;
    }

    for (size_t pos = 0; pos < dataLen;) {
        ssize_t stat = m_socket->Send(outBuffer + pos, dataLen - pos);
        if (stat < 0) {
            ERR("Socket send failed: %s.", strerror(errno));
            free(outBuffer);
            return stat;
        } else {
            pos = pos + static_cast<size_t>(stat);
        }
    }
    free(outBuffer);
    return static_cast<int>(len);
}